﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CustomTypes.Interfaces;
using CustomTypes.Interfaces.Structure;
using Microsoft.VisualStudio.Modeling;

namespace devtm.AutoMapper
{
    
    public class TypeRepository : IServiceProvider
    {


        public EventHandler<AssemblyResolveEventArgs> AssemblyResolver;

        private Dictionary<string, ITypeContext> _dic = new Dictionary<string, ITypeContext>();

        public TypeRepository()
        {
            
        }

        public CustomType GetType(CodeDomHelper.Types.TypeExpression type)
        {
            
            return GetType( type.AssemblyName,  type.Namespace,  type.Name);

        }

        public CustomType GetType(string assemblyName, string @namespace, string name)
        {

            string _assemblyName = assemblyName.Split(',')[0];


            if (_dic.ContainsKey(_assemblyName))
            {
                var ass = _dic[_assemblyName];
                return ass.GetType(@namespace, name);
            }
            else
            {

                ITypeContext ass = FindAssembly(_assemblyName);
                if (ass != null)                
                    return ass.GetType(@namespace, name);
                
            }

            return null;

        }

        public IEnumerable<CustomType> GetTypes(string assemblyName, HashSet<string> namespaces)
        {

            string _assemblyName = assemblyName.Split(',')[0];

            if (_dic.ContainsKey(_assemblyName))
            {

                var ass = _dic[_assemblyName];

                foreach (var item in ass.GetTypes(namespaces))
                    yield return item;

            }
            else
            {

                ITypeContext ass = FindAssembly(_assemblyName);
                if (ass != null)
                    foreach (var item in ass.GetTypes(namespaces))
                        yield return item;

            }

        }

        public IEnumerable<CustomType> GetTypes(string assemblyName)
        {

            string _assemblyName = assemblyName.Split(',')[0];

            if (_dic.ContainsKey(_assemblyName))
            {

                var ass = _dic[_assemblyName];

                foreach (var item in ass.GetTypes(null))
                    yield return item;

            }
            else
            {

                ITypeContext ass = FindAssembly(_assemblyName);
                if (ass != null)
                    foreach (var item in ass.GetTypes(null))
                        yield return item;

            }

            
        }



        public bool Contains(string assemblyName)
        {
            string _assemblyName = assemblyName.Split(',')[0];
            return _dic.ContainsKey(_assemblyName);
        }



        public IEnumerable<CustomType> GetTypes()
        {

            foreach (var item in _dic)            
                foreach (var type in item.Value.GetTypes(null))
                    yield return type;
            
        }


        private ITypeContext FindAssembly(string assemblyName)
        {

            var prj = new VisualStudio.ParsingSolution.Project(ContainingProject);

            foreach (EnvDTE.Project item in prj.GetReferencedProjectListe(false))
            {

                var prj2 = new VisualStudio.ParsingSolution.Project(item);
                if (!_dic.ContainsKey(prj2.AssemblyName))
                {
                    CSharpParser.TypeContext t = new CSharpParser.TypeContext(item);
                    _dic.Add(prj2.AssemblyName, t);

                    if (assemblyName == prj2.AssemblyName)
                        return t;

                }


            }

            foreach (var item in prj.GetReferencesListeNoInSolution())
            {
                CustomTypes.Mono.TypeContext t = new CustomTypes.Mono.TypeContext(item.Path);


                string NewAssemblyName = t.AssemblyName.Split(',')[0];

                if (!_dic.ContainsKey(NewAssemblyName))
                {
                    _dic.Add(NewAssemblyName, t);

                    if (assemblyName == NewAssemblyName)
                        return t;

                }
            }

            return null;

        }



        private Store _store;

        public Store Store 
        { 
            get
            {
                return _store;
            }
            set
            {
                _store = value;
                ContainingProject = Store2DTE.GetProjectForStore(this.Store);        
            }
        }

        public EnvDTE.Project ContainingProject { get; set; }


        public object GetService(Type serviceType)
        {
            return _store.GetService(serviceType);
        }

    }
}
